<script setup lang="ts">
import { getProcessDefinitionXml, saveProcessDefinitionXml } from '@/api/process'
import piniaStore from '@/stores'
import useBPMNStore from '@/stores/bpmnStore'
import customTranslate from '@/utils/bpmn/customTranslater'
import { xmlStr } from '@/utils/bpmn/xmlStr'

/**
 * 从 bpmn-js-properties-panel 包中引入模块，用于支持属性面板功能。
 */
import {
  BpmnPropertiesPanelModule,
  BpmnPropertiesProviderModule,
  CamundaPlatformPropertiesProviderModule,
} from 'bpmn-js-properties-panel'

/**
 * 引入 BpmnModeler 类，用于创建和操作 BPMN 图表。
 */
import BpmnModeler from 'bpmn-js/lib/Modeler'

/**
 * 引入 Camunda Moddle 描述符，用于扩展 BPMN 模型以支持 Camunda 特性。
 */
import CamundaBpmnModdle from 'camunda-bpmn-moddle/resources/camunda.json'

// 引入 Element Plus 的消息提示组件
import { ElMessage } from 'element-plus'

/**
 * 从 Vue 中引入生命周期钩子和响应式引用。
 */
import { onMounted, ref } from 'vue'

// 使用BPMN小仓库
const bpmnStore = useBPMNStore(piniaStore)

/**
 * 定义 canvasRef，用于引用 BPMN 图表的容器 DOM 元素。
 */
const canvasRef = ref<HTMLDivElement | null>(null)

/**
 * 定义 propertiesPanelRef，用于引用属性面板的容器 DOM 元素。
 */
const propertiesPanelRef = ref<HTMLDivElement | null>(null)

/**
 * 定义 modeler 变量，用于存储 BpmnModeler 实例。
 */
let modeler: BpmnModeler | null = null

// 当组件挂载时，异步初始化BPMN建模器
onMounted(async () => {
  await initializeBpmnModeler()
})

/**
 * 异步函数：初始化 BPMN 模型器
 *
 * 该函数负责初始化 BPMN 模型器实例，并根据提供的 processKey 加载相应的 BPMN XML 文件
 * 如果指定的 XML 文件不存在，则加载一个默认的 XML 文件
 */
async function initializeBpmnModeler() {
  // 检查 canvas 和 properties panel 的引用是否存在
  if (canvasRef.value && propertiesPanelRef.value) {
    // 翻译转换器
    const translateModule = {
      translate: ['value', customTranslate],
    }

    // 初始化 BpmnModeler 实例，配置容器、属性面板和扩展模块
    modeler = new BpmnModeler({
      container: canvasRef.value,
      propertiesPanel: {
        parent: propertiesPanelRef.value,
      },
      additionalModules: [
        BpmnPropertiesPanelModule,
        BpmnPropertiesProviderModule,
        CamundaPlatformPropertiesProviderModule,
        // 自定义翻译转换器
        translateModule,
      ],
      moddleExtensions: {
        camunda: CamundaBpmnModdle,
      },
    })

    // 根据 pinia 中的 processKey 查询BPMN XML
    // const xmlStr1 = await getXml(bpmnStore.processKey)
    const xmlStr1 = undefined
    if (xmlStr1) {
      // 导入 BPMN XML 字符串并处理成功后的逻辑
      await modeler.importXML(xmlStr1).then(() => {
        // 成功后操作（此处可添加具体逻辑）。
      })
    }
    else {
      // 导入默认字符串并处理成功后的逻辑
      await modeler.importXML(xmlStr).then(() => {
        // 成功后操作（此处可添加具体逻辑）。
      })
    }
  }
}

/**
 * 根据流程键获取XML定义
 *
 * 此函数调用`getProcessDefinitionXml`来获取流程定义的XML
 * 如果调用成功且返回代码为200，则返回XML数据，否则返回空字符串
 *
 * @param processKey 可选参数，用于指定流程的唯一键
 * @returns 成功时返回流程定义的XML，否则返回空字符串
 */
async function getXml(processKey?: string) {
  // 获取xml
  const result: any = await getProcessDefinitionXml({
    processKey,
  })

  if (result.success && result.code === 200) {
    return result.data
  }
  else {
    return ''
  }
}

/**
 * 异步保存函数
 * 该函数负责将模型编辑器中的XML数据保存到服务器
 */
async function onSave() {
  // 定义 processXmlParam，允许为 string 或 undefined
  let processXmlParam: string | undefined

  try {
    // 保存逻辑：获取格式化后的XML字符串
    const { xml } = await modeler?.saveXML({ format: true }) || {}
    if (xml !== undefined) {
      processXmlParam = xml // 如果xml存在，则赋值
    }
    else {
      processXmlParam = '' // 如果xml不存在，设置为空字符串
    }

    // 调用接口保存XML
    const result: any = await saveProcessDefinitionXml({
      processKey: bpmnStore.processKey,
      processXml: processXmlParam || '', // 确保传递的参数为字符串
    })

    // 根据保存结果执行相应的操作
    if (result.success && result.code === 200) {
      ElMessage({
        message: '保存成功',
        type: 'success',
      })
    }
    else {
      ElMessage({
        message: '保存失败',
        type: 'error',
      })
    }
  }
  catch (error) {
    // 处理异常
    let errorMessage = '未知错误'
    if (error instanceof Error) {
      errorMessage = error.message
    }
    // 显示错误消息
    ElMessage({
      message: `保存失败: ${errorMessage || '未知错误'}`,
      type: 'error',
    })
  }
}
</script>

<template>
  <div class="bpmn-container">
    <div class="save-btn">
      <el-button type="primary" @click="onSave">
        保存
      </el-button>
      <el-button type="primary" @click="onSave">
        导出
      </el-button>
    </div>
    <!-- bpmn区域 -->
    <el-row class="editor-wrapper">
      <el-col :span="18" class="canvas-col">
        <div ref="canvasRef" class="canvas" />
      </el-col>
      <el-col :span="6" class="panel-col">
        <div ref="propertiesPanelRef" class="properties-panel" />
      </el-col>
    </el-row>
  </div>
</template>

<style scoped>
/* 基础布局 */
.bpmn-container {
  height: 83vh;
  display: flex;
  flex-direction: column;
  background: #f5f5f5;
}

.save-btn {
  margin: 8px;
  position: relative;
}

.editor-wrapper {
  flex: 1;
  min-height: 0; /* 修复 flex 布局滚动问题 */
  margin: 0 12px 12px;
  background: white;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

/* 画布区域 */
.canvas-col {
  height: 100%;
  border-right: 1px solid #ebeef5;
  overflow: hidden;
}

.canvas {
  height: 100%;
  min-height: 600px; /* 最小高度保证内容可见 */
}

/* 属性面板 */
.panel-col {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.properties-panel {
  flex: 1;
  overflow-y: auto;
  padding: 12px;
  background: #fafafa;
}

/* 滚动条美化 */
.properties-panel::-webkit-scrollbar {
  width: 6px;
}

.properties-panel::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 3px;
}

.properties-panel::-webkit-scrollbar-track {
  background: #f1f1f1;
}
</style>
